#ifndef SD_CONFIG_HPP
#define SD_CONFIG_HPP


#ifndef MT // Minh-Tri's namespace
#define MT sd
// #define MT mt
#endif


#include "dtype.hpp"


#include <cstdio>
#if defined(_MATLAB_)
#define myprintf mexPrintf
#else
#define myprintf std::printf
#define USE_BOOST_SERIALIZATION // use boost::serialization
#endif


#ifdef TARGET_COMPILER_VC
#ifndef _USE_MATH_DEFINES
#define _USE_MATH_DEFINES
#endif
#endif


#pragma warning(disable:4800)


#ifdef USE_BOOST_SERIALIZATION
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/array.hpp>
#include <boost/serialization/split_member.hpp>
#define EIGEN_MATRIXBASE_PLUGIN "sd/Eigen_MatrixBase_BoostSerialization_Addon.hpp"
#endif
#include "Eigen/Dense"
#include "Eigen/Sparse"
#include "Eigen/StdVector"

#include <cmath>
#include <cstdlib>
#include <vector>
#include <utility>

#ifndef M_PI
#define M_PI        3.141592653589793238462643
#define M_PI_2		1.57079632679489661923
#define M_PI_4		0.78539816339744830962
#define M_1_PI		0.31830988618379067154
#define M_2_PI		0.63661977236758134308
#define M_2_SQRTPI	1.12837916709551257390
#endif


#ifdef USE_BOOST_SERIALIZATION
#include <boost/serialization/vector.hpp>
#include <boost/serialization/utility.hpp>


namespace boost {
namespace serialization {

/*template<class Archive, typename _Scalar>
inline void save(Archive & ar, Eigen::SparseVector<_Scalar> const &t, const unsigned int file_version)
{
    ar << make_nvp("size", t.m_size);
    int N = t.m_data.size();
    ar << make_nvp("actual_size", N);
    ar << make_nvp("indices", make_array(&t.m_data.index(0), N));
    ar << make_nvp("values", make_array(&t.m_data.value(0), N));
}

template<class Archive, typename _Scalar>
inline void load(Archive & ar, Eigen::SparseVector<_Scalar> &t, const unsigned int file_version)
{
    int size, N;
    ar >> make_nvp("size", size) >> make_nvp("actual_size", N);
    t.resize(size); t.m_data.resize(N);
    ar >> make_nvp("indices", make_array(&t.m_data.index(0), N));
    ar >> make_nvp("values", make_array(&t.m_data.value(0), N));
}

template<class Archive, typename _Scalar>
inline void serialize(Archive & ar, Eigen::SparseVector<_Scalar> &t, const unsigned int file_version)
{
    split_free(ar, t, file_version);
}
*/

// fix for eigen's stl vector
#ifdef _MSC_VER
template<class Archive, typename _Scalar>
inline void serialize(Archive & ar, Eigen::ei_workaround_msvc_stl_support<_Scalar> &t, const unsigned int file_version)
{
	serialize(ar, (_Scalar)t, file_version);
}
#endif

} // namespace serialization
} // namespace boost


#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/fstream.hpp>


namespace MT {

namespace bfs = ::boost::filesystem;

// read a matrix from file
template<typename _Scalar, int _Rows>
bool read_matrix_from_file(bfs::path const &filename, Eigen::Matrix<_Scalar, _Rows, Eigen::Dynamic> &mat, int rows=-1)
{
    if(_Rows != Eigen::Dynamic) rows = _Rows;
    ei_assert(rows != Eigen::Dynamic && "The number of items per element must be specified.");

    // get file size
	int file_size = (int) bfs::file_size(filename);

    int cols = file_size / (sizeof(_Scalar)*rows);

    // allocate memory
    mat.resize(rows, cols);

	// open file
    bfs::ifstream ifs(filename, std::ios::binary | std::ios::in);

    // load the stuff
    ifs.read((char *)mat.data(), file_size);

    return true;
}

// write a matrix to file, it's up to the user to decide how to read the file
template<typename _Scalar, int _Rows>
bool write_matrix_to_file(bfs::path const &filename, Eigen::Matrix<_Scalar, _Rows, Eigen::Dynamic> const &mat)
{
	int rows = mat.rows(), cols = mat.cols();

    // open file and get file size
    bfs::ofstream ofs(filename, std::ios::binary | std::ios::out);

	int file_size = rows*cols*sizeof(_Scalar);

    // dump the stuff
    ofs.write((char *)mat.data(), file_size);

    return true;
}



} // namespace MT
#endif

#endif
